#if !defined(TEST_INTERVALS_PER_CONTIG_H)
#define TEST_INTERVALS_PER_CONTIG_H


#include <string>
#include <vector>
#include <map>
#include <iostream>
#include <boost/tr1/unordered_map.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>

namespace discrete_intervals_per_contig
{
	namespace fs = boost::filesystem;
	
	struct t_interval
	{
		unsigned                    beg;
		unsigned                    end;
		unsigned                    id;
		t_interval(){}
		t_interval(unsigned beg_, unsigned end_, unsigned id_ = 0): beg(beg_), end(end_), id(id_){}
		t_interval(const t_interval& other ): beg(other.beg), end(other.end), id(other.id){}
	};
	inline bool operator <(const t_interval& me, const t_interval& other)
	{
		if (me.end == other.end)
			return me.beg < other.beg;
		return me.end < other.end;
	}

	struct t_sort_by_beg
	{
		bool operator()(const t_interval& me, const t_interval& other)
		{
			if (me.beg == other.beg)
				return me.end < other.end;
			return me.beg < other.beg;
		}
	};
	typedef std::vector<t_interval> 							t_intervals;
	typedef std::vector<t_interval>::iterator 					i_intervals;

	typedef std::tr1::unordered_map<std::string, t_intervals > 	t_intervals_by_contig;
	typedef t_intervals_by_contig::iterator 					i_intervals_by_contig;
	
	//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
	// 
	//     t_discrete_intervals

	//		Non-overlapping intervals	
	// 		Uses open closed coordinates
	// 
	//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
	struct t_discrete_intervals
	{
									t_discrete_intervals();
		t_intervals_by_contig 		intervals_by_contig;
		i_intervals					i_prev_interval;
		i_intervals					i_next_interval;
		std::string     			curr_contig;
		i_intervals_by_contig		curr_contig_intervals;

		void						expand_by(unsigned by);
		void						combine_close_neighbours(unsigned min_distance);
		void						combine_overlapping () {combine_close_neighbours(0);}
		bool 						contains(std::string discrete_contig, unsigned test_pos);
		bool						any_closest(std::string test_contig, unsigned test_pos, unsigned& dist, i_intervals& closest_interval);

		void						init();
		unsigned					total_count() const;
		unsigned					total_size() const ;
			// get sorted contig names
		std::vector<std::string> 	get_sorted_contigs() const;

	private:
		bool						within_flanking_interval_pair(unsigned test_pos, unsigned& dist, i_intervals& closest_interval) const;
		bool						within_flanking_interval_pair(unsigned test_pos) const;
		void						increment_flanking_interval_pair();
		void						get_flanking_intervals(unsigned test_pos);
		bool						set_curr_contig(const std::string& test_contig);


	};


	// 
	// read and write
	// 
	void write_intervals(	std::ostream& 					f_intervals, 
							const t_discrete_intervals& 	intervals, 
							bool 							inclusive_coordinates = true,
							const std::string&				interval_type_name = std::string()
							);
	void read_intervals(std::istream& f_intervals, t_discrete_intervals& intervals_by_contig, bool inclusive_coordinates = true);


	typedef std::vector<t_discrete_intervals> 	t_vec_discrete_intervals;
	typedef t_vec_discrete_intervals::iterator 	i_vec_discrete_intervals;

	void write_intervals_by_type(	std::ostream& 						f_intervals, 
									std::map<std::string, unsigned>&	map_interval_type_to_index, 
									std::vector<std::string> 			interval_type_names, 
									t_vec_discrete_intervals& 			intervals_by_contig_by_type,
									bool 								inclusive_coordinates);
	void read_intervals_by_type(std::istream& 						f_intervals, 
								t_vec_discrete_intervals& 			intervals_by_contig_by_type, 
								std::map<std::string, unsigned>& 	map_interval_type_to_index, 
								std::vector<std::string>& 			additional_interval_types, 
								bool 								inclusive_coordinates = true);

	//
	//  use of map deprecated
	// 
	typedef std::tr1::unordered_map<std::string, t_discrete_intervals> 	t_discrete_intervals_by_type;
	typedef t_discrete_intervals_by_type::iterator 	i_discrete_intervals_by_type;
	//void read_intervals_by_type(t_discrete_intervals_by_type& intervals_by_contig_by_type, std::istream& f_intervals, bool inclusive_coordinates = true);
};

#endif	// TEST_INTERVALS_PER_CONTIG_H
